#include <assert.h>
#include <math.h>
#include "particle.h"

//using namespace physics;

physics::Particle::Particle(ID3DXSprite* sprite, SpriteData &spriteData, float scale, float velocity, float angularVelocity, float lifeTime, physics::Vector3 position, bool alphaFade) : RigidBody()
{
	float x = GetRandomFloat(-1.0f, 1.0f);
	float y = GetRandomFloat(-1.0f, 1.0f);
	float z = GetRandomFloat(-1.0f, 1.0f);
	float r = GetRandomFloat(-1.0f, 1.0f);

	physics::Vector3 t(0, 0, r);
	t.normalize();
	t *= angularVelocity;
	Particle::rotation = t;

	physics::Vector3 v(x, y, z);
	v.normalize();
	v *= velocity;
	Particle::velocity = v;

	mSprite = new Sprite(sprite, spriteData, scale, lifeTime, alphaFade);
	Particle::position = position;

	Particle::setMass(1.0f);
	Particle::setDamping(1.0f, 1.0f);
}

physics::Particle::~Particle(void)
{
	delete mSprite;
}

//////////////////////////////////////////////
// integrate()
// 
// Integrates the particles position by the current velocity
// and updates the velocity for the next iteration based on the currently-applied
// forces. Since this is cyclical in nature, the order is not particularly important
//////////////////////////////////////////////
void physics::Particle::integrate(real dt)
{
	// update the sprite
	mSprite->Update(dt);

	// object is either infinitely massive, broken 
	// or not properly initialized, so no calculations 
	// are needed.
	if (inverseMass <= 0.0f) return; 

	// if we get a negative or zero value for the amount
	// of time that has passed, we have an error in our 
	// time calculations
	assert(dt > 0.0f); 

	// update the position based on the current velocity
	position.addScaledVector(velocity, dt);
	orientation.addScaledVector(rotation, dt);	

	// generate the acceleration from the forces
	// applied to this object
	Vector3 resultingAcc = acceleration;
	resultingAcc.addScaledVector(forceAccum, inverseMass); // a = f/m

	// update linear velocity from acceleration for the next iteration step
	velocity.addScaledVector(resultingAcc, dt);

	// impose drag
	velocity *= real_pow(linearDamping, dt);
	rotation *= real_pow(angularDamping, dt);

	calculateDerivedData();

	// zero the applied forces in preparation
	// for the next interation step
	clearAccumulators();

	
}

void physics::Particle::Render(D3DXMATRIX &viewProj)
{
	D3DXVECTOR3 pos;
	pos.x = position.x;
	pos.y = position.y;
	pos.z = position.z;

	//float orientation = Particle::orientation.k;
	Quaternion q = Particle::getOrientation();
	physics::Matrix3 m;
	m.setOrientation(q);

	D3DMATRIX rot = m.ConvertToDX();

	//float orientation = 0.0f;

	//mSprite->Render(viewProj, pos, orientation);
	mSprite->Render(viewProj, pos, rot);
}